package chapter01.part11;

import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Stream;

import static java.util.stream.Collectors.*;

/**
 * 下游收集 学习 groupingBy() 的第二个参数的用法
 *
 * @author insight
 * @since 2021/7/22
 */
public class DownStreamCollector {
    public static void main(String[] args) {
        Supplier<Stream<Locale>> locales = () ->
                Stream.of(Locale.getAvailableLocales());
        Supplier<Stream<City>> city = getCitiesStream();

        // 默认是 List 但可以使用别的集合
        Map<String, Set<Locale>> countryToLocaleSet = locales.get().collect(
                groupingBy(Locale::getCountry, toSet())
        );
        System.out.println(countryToLocaleSet);
        
        // 还有多种把结果约简为数字的方法
        // count
        Map<String, Long> countryToLocaleCnt = locales.get().collect(
                groupingBy(Locale::getCountry, counting())
        );
        System.out.println(countryToLocaleCnt);
        
        // sum
        Map<String, Long> countryToLocaleSum = city.get().collect(
                groupingBy(City::getState, summingLong(City::getPopulation))
        );
        System.out.println(countryToLocaleSum);
        
        // max 计算每个省人口最多的城市
        Map<String, Optional<City>> countryToLocaleMax = city.get().collect(
                groupingBy(City::getState,
                    maxBy(Comparator.comparing(City::getPopulation)))
        );
        countryToLocaleMax.forEach((k, v) -> System.out.println(k + " " + v.get().getName()));
        
        // 收集后继续操作
        Map<String, Integer> countryToLocaleSetSize = locales.get().collect(
                groupingBy(Locale::getCountry,
                    collectingAndThen(toSet(), Set::size))
        );
        System.out.println(countryToLocaleSetSize);
        
        // mapping 则顺序颠倒 先处理 再收集
        Map<String, Set<String>> countryToLocaleWithMapping = locales.get().collect(
                groupingBy(Locale::getCountry,
                        mapping(locale -> locale.getDisplayLanguage(locale), toSet()))
        );
        System.out.println(countryToLocaleWithMapping);

        // 汇总统计
        Map<String, IntSummaryStatistics> countryToLocaleWithSum = city.get().collect(
                groupingBy(City::getState,
                        summarizingInt(City::getPopulation))
        );
        System.out.println(countryToLocaleWithSum);
        
        // filtering in each group
        Map<String, Set<City>> countryToLocaleWithFilter = city.get().collect(
                groupingBy(City::getState,
                        filtering(c -> c.getPopulation() > 10000000, toSet()))
        );
        System.out.println(countryToLocaleWithFilter);
    }
    
    public static Supplier<Stream<City>> getCitiesStream() {
        return () -> Stream.of(
                new City("重庆", "重庆", 32054159),
                new City("苏州", "江苏", 12748262),
                new City("南京", "江苏", 8335000),
                new City("广州", "广东", 15305900),
                new City("深圳", "广东", 17560061),
                new City("阿那亚", "河北", 0)
        );
    }

    @AllArgsConstructor
    @Getter
    public static class City {
        private String name;
        private String state;
        private int population;
    }
}